package com.thinkmore.es.test.bean;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class SearchUtil {

    protected static Logger log = LoggerFactory.getLogger(SearchUtil.class);

    public static EsResult commonSearch(SearchParam searchParam) {
        String indexName = searchParam.getIndexName();
        if (indexName == null) {
            indexName = EsConfig.indexName;
        }
        return commonSearch(indexName, searchParam);
    }

    public static EsResult commonSearch(String indexName, SearchParam searchParam) {
        RestHighLevelClient client = EsConfig.init();
        EsResult esResult = null;
        try {
            if (searchParam == null) {
                searchParam = new SearchParam();
                //return EsUtil.fail(null, "500", "searchBean is null");
            }
            searchParam.setRequestId("");
            SearchSourceBuilder searchSourceBuilder = searchParam.getSearchSourceBuilder();
            if (searchSourceBuilder == null) {
                searchSourceBuilder = new SearchSourceBuilder();
            }
            if (searchParam.getRequestType() == 0) {
                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                Map<String, SearchField> param = searchParam.getSearchParam();
                if (param != null && param.size() > 0) {
                    for (Map.Entry<String, SearchField> entry : param.entrySet()) {
                        SearchField searchField = entry.getValue();
                        QueryType queryType = searchField.getQueryType();
                        Object searchValue = searchField.getFieldValue();
                        QueryBuilder queryBuilder = null;
                        if (queryType == QueryType.MATCH) {
                            queryBuilder = QueryBuilders.matchQuery(searchField.getFieldName(), searchValue);
                        } else if (queryType == QueryType.TERMS) {
                            queryBuilder = QueryBuilders.termsQuery(searchField.getFieldName(), searchValue);
                        } else {
                            queryBuilder = QueryBuilders.termQuery(searchField.getFieldName(), searchValue);
                        }
                        if (searchField.getQueryOperateType() == QueryOperateType.SHOULD) {
                            boolQuery.should(queryBuilder);
                        } else if (searchField.getQueryOperateType() == QueryOperateType.MUST_NOT) {
                            boolQuery.mustNot(queryBuilder);
                        } else {
                            boolQuery.must(queryBuilder);
                        }
                    }
                }
            /*RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("xxx");
            rangeQueryBuilder.gte(26).lte(29);
            boolQuery.filter(rangeQueryBuilder);*/
                Map<String, SortType> sortParam = searchParam.getSortParam();
                if (sortParam != null && sortParam.size() > 0) {
                    for (Map.Entry<String, SortType> entry : sortParam.entrySet()) {
                        SortType sortType = entry.getValue();
                        searchSourceBuilder.sort(entry.getKey(), (sortType == null || sortType == SortType.ASC) ? SortOrder.ASC : SortOrder.DESC);
                    }
                }
                searchSourceBuilder.query(boolQuery);
                searchSourceBuilder.from(0);
                searchSourceBuilder.size(searchParam.getPageSize());
            } else if (searchParam.getRequestType() == 3) {
                searchSourceBuilder.query(QueryBuilders.wrapperQuery(searchParam.getRequestBody()));
            }

            //这句代码就是设置游标查询和过期时间，1m就是1分钟之内scrollId有效
            Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1));
            String scrollId = searchParam.getScrollId();
            SearchResponse response = null;
            if (StringUtils.isBlank(scrollId)) {
                SearchRequest request = new SearchRequest(indexName);
                request.scroll(scroll);
                request.source(searchSourceBuilder);
                response = client.search(request, RequestOptions.DEFAULT);
            } else {
                //这里面保存的是上一步的结果，比如：[1577973600000,"file3"]，第一个值是时间，第二个是id，对应的是上面searchSourceBuilder.sort的顺序
                //Object[] sortValues = searchHits[0].getSortValues();
                Object[] sortValues = searchParam.getSortValues();
                //注意这里的设置
                searchSourceBuilder.searchAfter(sortValues);
                SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
                scrollRequest.scroll(scroll);
                response = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            }
            esResult = EsUtil.ok(searchParam, response);
        } catch (Exception e) {
            esResult = EsUtil.fail(searchParam, "searchError", "查询出错");
            if (e.getMessage().contains("search_phase_execution_exception")) {
                esResult.setExpMsg(e.getMessage() + ",可能原因：参数类型不正确");
            } else {
                esResult.setExpMsg(e.getMessage());
            }
            log.error("searchError:", e);
        }
        return esResult;
    }
}
